前面說那麼多次以後會遇到大型專案會怎樣怎樣的,所以現在就要來說一下大型專案長怎樣,如何將大型專案拆解開來看,讓你不會拿到一大包東西完全不知如何下手。
話說因為 Flask 本身就是小框架,也沒太多重要的或常用的東西可以講;再加上我是想把 Flask 本體講完再講其他的啦,所以這篇算是有關 Flask 本體的最後一篇了。下一篇就會進入到 Flask 插件的部分(是說上一篇其實就有講到插件了)。
如果網站架構持續運作了好幾年,中間不斷地修修改改,功能越來越多,架構越來龐大,將全部的路由都放在一個檔案裏面會造成維護上的困難,所以勢必要將不同功能的路由拆成不同檔案,以利維護。
而 Blueprints 是 Flask 提供的將不同功能的路由模組化管理的方式,不過路由是分開了,那前端視圖跟靜態文件呢?
如果不做設定,前端視圖跟靜態文件還是在 templates
跟 static
裡面,這樣的優點是不同模組間能夠套用同樣的父視圖(base.html
那個東東);而如果想要不同模組間可以有不同的視圖,也能夠分開擺放(也可以一部份分開,一部分放一起)。
那就直接來看如何使用吧。讓我們拿前面的架構再來改一下:
ithome
├── account # 取個有意義的名字
│ └── api.py # 隨便取個名字
├── static
│ └── logo.png
├── templates
│ ├── account # 它改個有意義的名字
│ │ ├── home.html
│ │ ├── login.html
│ │ └── settings.html
│ ├── base.html
│ ├── index.html
│ └── page_not_found.html
├── app.py
├── configs.py
├── Pipfile
└── Pipfile.lock
然後將 app.py
裡面的 home, login, settings 搬進去 account -> api.py
裡面,再各加上幾行。
然後因為移動了 index.html
跟 page_not_found.html
,還有改了 res
的資料夾名稱,所以有關 render_template
的都需要改一下;以及路由需要修正一下。
app.py
裡面應該剩這樣:
from flask import Flask, render_template, make_response
# 這個 app 是 api.py 裡面的 app,建議改個有意義的名字,同樣都叫 app 是我懶得改
# 如果名稱衝突到,可以使用 as 來取個暱稱。
from account.api import app as account
from configs import config
app = Flask(__name__)
app.config.from_object(config.DevelopmentConfig)
# 註冊 blueprint
app.register_blueprint(account)
# 這邊的 app 是上面 Flask 的 app
@ app.route('/')
def index():
return render_template('index.html')
''' 應該還有一些其他的東西,不過這裡沒有要用到,註解掉或刪掉都沒關係 '''
@ app.errorhandler(404)
def page_not_found(error):
response = make_response(render_template(
'page_not_found.html', error=error), 404)
return response
if __name__ == "__main__":
app.run()
前面的那三個路由搬到 api.py
裡面,有關 render_template
的記得改一下。
# 新增這行
from flask import Blueprint, redirect, request, render_template, make_response, url_for
# 還有新增這行,同樣叫 app 只是我懶得改,建議還是改有意義的名字。
app = Blueprint('account', __name__)
@app.route('/home', methods=['GET'])
def home():
if 'username' in request.cookies:
user = request.cookies.get('username')
return render_template('account/home.html', username=user)
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
response = make_response(render_template('account/login.html'))
elif request.method == 'POST': # 表單送出後會到這裡
account = request.values.get('username', None)
# 驗證是否有這個使用者以及密碼是否正確,生出驗證結果 auth_result
auth_result = 'success' # 假設成功
''' 建立回應 '''
if auth_result == 'success': # 如果都正確
response = make_response(redirect(url_for('account.home')))
response.set_cookie('username', account) # 先使用 Cookie 就好
else: # 如果錯誤
response = make_response(redirect(url_for('account.login')))
else:
response = make_response(redirect(url_for('index')))
return response
@app.route('/settings', methods=['GET'])
def settings():
if 'username' in request.cookies:
user = request.cookies.get('username')
return render_template('account/settings.html', username=user)
改到這裡就差不多了,如果在 .html
裡面有使用到 url_for
的要記得改一下。例如 url_for('login')
要改成 url_for('account.login')
,前面加 Blueprint 中的第一個參數還有英文句號就 OK 了(還有不是那個 Blueprint 下的路由前面不要亂給他加名稱,不要亂認親)。
如果要改的都有改到的話,這幾個功能應該跟移動之前是差不多的,不過這幾個功能就分開來了,在維護時也能更快、更輕鬆的維護。
如果要將前端視圖與靜態文件分開,首先至少要將它們搬到相應的位置對吧。
ithome
├── account
│ ├── static_account
│ │ └── logo.png
│ ├── templates_account
│ │ ├── account # 因為我不想改 render_template,所以就留著它了。
│ │ │ ├── home.html
│ │ │ ├── login.html
│ │ │ └── settings.html
│ │ └── base.html
│ └── api.py
├── static
│ └── logo.png
├── templates
│ ├── base.html
│ ├── index.html
│ └── page_not_found.html
├── app.py
├── configs.py
├── Pipfile
└── Pipfile.lock
搬完之後,再到 api.py
設定新的前端視圖與靜態文件位置,
api.py
from flask import Blueprint, redirect, request, render_template, make_response, url_for
app = Blueprint('account', __name__, static_folder='static_account',
static_url_path='/img', template_folder='templates_account',
url_prefix='/account')
@app.route('/home', methods=['GET'])
def home():
if 'username' in request.cookies:
user = request.cookies.get('username')
return render_template('account/home.html', username=user)
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
response = make_response(render_template('account/login.html'))
elif request.method == 'POST': # 表單送出後會到這裡
account = request.values.get('username', None)
# 驗證是否有這個使用者以及密碼是否正確,生出驗證結果 auth_result
auth_result = 'success' # 假設成功
''' 建立回應 '''
if auth_result == 'success': # 如果都正確
response = make_response(redirect(url_for('account.home')))
response.set_cookie('username', account) # 先使用 Cookie 就好
else: # 如果錯誤
response = make_response(redirect(url_for('account.login')))
else:
response = make_response(redirect(url_for('index')))
return response
@app.route('/settings', methods=['GET'])
def settings():
if 'username' in request.cookies:
user = request.cookies.get('username')
return render_template('account/settings.html', username=user)
Blueprint 一樣有著 static_folder
、 static_url_path
、 template_folder
,用法也跟 Day 17 一樣。而 url_prefix
是什麼呢?
先來看看不加 url_prefix
會發生什麼事。
再來看看加了 url_prefix
會發生什麼事。
有注意到 url 的變化嗎?就是在這個 Blueprint 裡面的路由都加上 url 前綴。
那麼就大概這樣,有關 Flask 本體大概就這樣就結束了,下一篇開始就是 Flask 的插件了。
大家掰~掰~